﻿using System;
using System.Text;
using System.Collections;
using System.Runtime.InteropServices;
using System.Drawing;
using Kn.DLMS;
using static WindowsFormsApplication3.Form1;
using System.Threading;
using System.Timers;
using Kn.Common;
using System.Collections.Concurrent;

namespace WindowsFormsApplication3
{
    /// <summary>
    /// 645协议通讯组件！！！！！！！！！！！！！
    /// </summary>
    public class CommProcess    //定义CommProcess类
    {

        #region 事件定义
        /// <summary>
        /// 发送命令帧显示
        /// </summary>
        public delegate void ShowSendCommandDeleage(object sender, bool bSuccess, string strSendData);    //委托类型
        public static event ShowSendCommandDeleage ShowSendCommand;                                       //事件名称ShowSendCommand              

        public delegate void ShowSendFrameCommandDeleage(string strSendData);                              //委托类型
        public delegate void ShowReceiceCommandDeleage(object sender, bool bSuccess, string strRecData);   //委托类型
        public static event ShowReceiceCommandDeleage ShowReceiceCommand;                                  //事件名称ShowReceiceCommand


        public delegate void SetTextHander(string txt);  //声明委托类型
        public  SetTextHander setTextHander;       //声明委托变量， 静态！！！

        public delegate void SetResultHander(string txt);  //声明委托类型
        public  SetResultHander setResultHander;       //声明委托变量， 静态！！！

        public delegate void SetErrorHander(string strEx);  //声明委托类型
        public  SetErrorHander setErrorHander;       //声明委托变量， 静态！！！

        public delegate void SetAlarmHander(Color a);  //声明委托类型
        public  SetAlarmHander setAlarmHander;       //声明委托变量， 静态！！！

        public ParserHandlerDelegate ParserHandler;   //接受到一帧完整 
        public ParserHandlerDelegate ReceiveHandler;  //接受到一帧完整

        private bool isReceiving;
        private const int TimeoutDuration = 800; // 超时时间，单位为毫秒
        private System.Timers.Timer timer;
        #endregion

        #region 私有成员
        int[] g_buf = new int[1024];
        byte[] g_byte = new byte[512];
        uint g_cnt = 0;
        uint g_reccnt = 0;


        /// <summary>
        /// 接收数据缓冲区
        /// </summary>
        public ArrayList alRecBuf = null;

        //接收完整数据
        private bool bReceice = false;

        /// <summary>
        /// 中断触发事件回调函数
        /// </summary>
        private Pcomm.CallBackIrqProc IrqProc_CallBack = null;

        /// <summary>
        /// 返回数据
        /// </summary>
        public string sReturnData = "";
        public static string ReturnData = "";  //返回类的静态全局变量

        /// <summary>
        /// 发送的数据
        /// </summary>
        public string sSendData = "";
        public static string SendData = "";   //发送类的静态全局变量

        public int nFound = -1;


        #endregion

        #region 公共成员
        public int gComm_iPort;              //通讯端口
        public int gComm_iBaudRate;          //通讯波特率
        public int gComm_iStopBit;           //通讯停止位
        public int gComm_iDataBit;           //通讯数据位
        public string gComm_strParity;       //通讯校验位
        public string gComm_strMeterAddress = "AAAAAAAAAAAA";  //通讯地址
        public int gComm_Delay = 20;

        /// <summary>
        /// Received reply data.
        /// </summary>
        public GXByteBuffer AliceMessage = new GXByteBuffer();

        public GXByteBuffer HDLCMessage = new GXByteBuffer();
        #endregion


        #region CommProcess类默认构造函数
        private void TimerElapsed(object sender, ElapsedEventArgs e)
        {
            timer.Stop();
            byte[] byteArray = new byte[alRecBuf.Count];
            for (int i = 0; i < alRecBuf.Count; i++)
            {
                byteArray[i] = Convert.ToByte(alRecBuf[i]);
            }
            AliceMessage.Set(byteArray);
            if (ParserHandler != null)
            {
                ParserHandler(byteArray);  //接收超时处理
            }

            this.alRecBuf.Clear();
            isReceiving = false;
        }
        public CommProcess()   //默认构造函数
        {
            timer = new System.Timers.Timer(TimeoutDuration); 
            timer.Elapsed += TimerElapsed;   //下行接收超时处理
        }
        #endregion

        #region CommProcess类 构造函数1
        public CommProcess(int iPort, int iBaudRate, int iStopBit, int iDataBit, string strParity, string strMeterAddress)   //默认构造函数
        {
            gComm_iPort = iPort;         //端口
            gComm_iBaudRate = iBaudRate; //波特率
            gComm_iStopBit = iStopBit;   //停止位
            gComm_iDataBit = iDataBit;   //数据位
            gComm_strParity = strParity; //校验位

            gComm_strMeterAddress = strMeterAddress; //通讯地址
        }
        #endregion

        #region 特率率转换[int BaudRateChange(int iBaudRate)]
        /// <summary>
        /// 特率率转换
        /// </summary>
        /// <param name="iBaudRate">波特率</param>
        /// <returns></returns>
        public int BaudRateChange(int iBaudRate)
        {
            switch (iBaudRate)
            {
                case 300:
                    return (int)Pcomm.BaudRate.B300;
                case 600:
                    return (int)Pcomm.BaudRate.B600;
                case 1200:
                    return (int)Pcomm.BaudRate.B1200;
                case 1800:
                    return (int)Pcomm.BaudRate.B1800;
                case 2400:
                    return (int)Pcomm.BaudRate.B2400;
                case 4800:
                    return (int)Pcomm.BaudRate.B4800;
                case 7200:
                    return (int)Pcomm.BaudRate.B7200;
                case 9600:
                    return (int)Pcomm.BaudRate.B9600;
                case 19200:
                    return (int)Pcomm.BaudRate.B19200;
                case 38400:
                    return (int)Pcomm.BaudRate.B38400;
                case 57600:
                    return (int)Pcomm.BaudRate.B57600;
                case 115200:
                    return (int)Pcomm.BaudRate.B115200;
                case 230400:
                    return (int)Pcomm.BaudRate.B230400;
                case 460800:
                    return (int)Pcomm.BaudRate.B460800;
                case 921600:
                    return (int)Pcomm.BaudRate.B921600;
            }

            return (int)Pcomm.BaudRate.B9600;
        }

        #endregion

        #region 校验位转换 int ParityChange(string sParity)

        /// <summary>
        /// 校验位转换
        /// </summary>
        /// <param name="sParity">校验位(N,E,O,S,M)</param>
        /// <returns></returns>
        public int PairtyChange(string sParity)
        {
            switch (sParity)
            {
                case "N":
                    return (int)Pcomm.Parity.P_NONE;
                case "E":
                    return (int)Pcomm.Parity.P_EVEN;
                case "O":
                    return (int)Pcomm.Parity.P_ODD;
                case "S":
                    return (int)Pcomm.Parity.P_SPC;
                case "M":
                    return (int)Pcomm.Parity.P_MRK;
            }

            return (int)Pcomm.Parity.P_NONE;
        }

        #endregion

        #region 停止位转换[int StopBitChange(int iStopBit)]
        /// <summary>
        ///停止位转换
        /// </summary>
        /// <param name="iStopBit">停止位(1,2)</param>
        /// <returns></returns>
        public int StopBitChange(int iStopBit)
        {
            switch (iStopBit)
            {
                case 1:
                    return (int)Pcomm.StopBit.STOP_1;
                case 2:
                    return (int)Pcomm.StopBit.STOP_2;
            }

            return (int)Pcomm.StopBit.STOP_1;
        }

        #endregion

        #region 数据位转换[int DataBitChange(int iDataBit)]

        /// <summary>
        /// 数据位转换
        /// </summary>
        /// <param name="iDataBit">数据位(5,6,7,8)</param>
        /// <returns></returns>
        public int DataBitChange(int iDataBit)
        {
            switch (iDataBit)
            {
                case 5:
                    return (int)Pcomm.DataBit.BIT_5;
                case 6:
                    return (int)Pcomm.DataBit.BIT_6;
                case 7:
                    return (int)Pcomm.DataBit.BIT_7;
                case 8:
                    return (int)Pcomm.DataBit.BIT_8;
            }

            return (int)Pcomm.DataBit.BIT_8;
        }

        #endregion

 
        #region 打开串口[ void OpenPort(int iPort,int iBaudRate,int iDataBit,int iStopBit,string strParity) ]

        /// <summary>
        /// 打开串口
        /// </summary>
        /// <param name="iPort">串口号(1,2,3.....)</param>
        /// <param name="iBaudRate">波特率(1200,9600....)</param>
        /// <param name="iDataBit">数据位(5,6,7,8)</param>
        /// <param name="iStopBit">停止位(1,2)</param>
        /// <param name="sParity">校验方式</param>
        public void OpenPort(int iPort, int iBaudRate, int iDataBit, int iStopBit, string strParity)
        {
            try
            {
                int ret = 0;

                //打开串口
                ret = Pcomm.sio_open(iPort);
                if (ret != (int)Pcomm.Error_Code.SIO_OK)
                {
                    throw new Exception(Pcomm.IoErrorMsg(ret));
                }

                //设置串口参数\
                gComm_iPort = iPort;
                int BaudRate = this.BaudRateChange(iBaudRate); //波特率
                int Parity = this.PairtyChange(strParity);     //校验方式
                int StopBit = this.StopBitChange(iStopBit);    //停止位
                int DataBit = this.DataBitChange(iDataBit);    //数据位
                int Mode = Parity | DataBit | StopBit;         //传输参数
                ret = Pcomm.sio_ioctl(iPort, BaudRate, Mode);
                if (ret != (int)Pcomm.Error_Code.SIO_OK)
                {
                    Pcomm.sio_close(iPort);
                    throw new Exception(Pcomm.IoErrorMsg(ret));
                }

                //设置中断回调函数设置!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                IrqProc_CallBack = new Pcomm.CallBackIrqProc(DataReceived); //???????????!!!!!!!!!!!!!!!!
                processDownThread = new Thread(ProcessDownData);              // 创建并启动处理统计线程
                processDownThread.Start();
                // 设置标志变量，停止处理线程
                stopDownProcessing = false;

                ret = Pcomm.sio_cnt_irq(iPort, IrqProc_CallBack, 1);            //每接收1个字节中断一次	
                if (ret != (int)Pcomm.Error_Code.SIO_OK)
                {
                    Pcomm.sio_close(iPort);
                    throw new Exception(Pcomm.IoErrorMsg(ret));
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        #endregion


        #region 打开串口[ void OpenPort(int iPort,int iBaudRate,int iDataBit,int iStopBit,string strParity) ]

        /// <summary>
        /// 打开串口
        /// </summary>
        /// <param name="iPort">串口号(1,2,3.....)</param>
        /// <param name="iBaudRate">波特率(1200,9600....)</param>
        /// <param name="iDataBit">数据位(5,6,7,8)</param>
        /// <param name="iStopBit">停止位(1,2)</param>
        /// <param name="sParity">校验方式</param>
        public void OpenPortUp(int iPort, int iBaudRate, int iDataBit, int iStopBit, string strParity)
        {
            try
            {
                int ret = 0;

                //打开串口
                ret = Pcomm.sio_open(iPort);
                if (ret != (int)Pcomm.Error_Code.SIO_OK)
                {
                    throw new Exception(Pcomm.IoErrorMsg(ret));
                }

                //设置串口参数\
                gComm_iPort = iPort;
                int BaudRate = this.BaudRateChange(iBaudRate); //波特率
                int Parity = this.PairtyChange(strParity);     //校验方式
                int StopBit = this.StopBitChange(iStopBit);    //停止位
                int DataBit = this.DataBitChange(iDataBit);    //数据位
                int Mode = Parity | DataBit | StopBit;         //传输参数
                ret = Pcomm.sio_ioctl(iPort, BaudRate, Mode);
                if (ret != (int)Pcomm.Error_Code.SIO_OK)
                {
                    Pcomm.sio_close(iPort);
                    throw new Exception(Pcomm.IoErrorMsg(ret));
                }

                //设置中断回调函数设置!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                IrqProc_CallBack = new Pcomm.CallBackIrqProc(UpDataReceived); //???????????!!!!!!!!!!!!!!!!

                processUpThread = new Thread(ProcessUpData);              // 创建并启动处理统计线程
                processUpThread.Start();
                // 设置标志变量，停止处理线程
                stopDownProcessing = false;


                ret = Pcomm.sio_cnt_irq(iPort, IrqProc_CallBack, 1);            //每接收1个字节中断一次	
                if (ret != (int)Pcomm.Error_Code.SIO_OK)
                {
                    Pcomm.sio_close(iPort);
                    throw new Exception(Pcomm.IoErrorMsg(ret));
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        #endregion


        #region 关闭串口[void ClosePort(int iPort)]
        /// <summary>
        /// 关闭串口
        /// </summary>
        public void ClosePort(int iPort)
        {
            try
            {
                int ret = 0;
                stopDownProcessing = true;
                ret = Pcomm.sio_close(iPort);                  //调用dll接口函数,关闭串口           

                if (ret != (int)Pcomm.Error_Code.SIO_OK)      //判断执行结果
                {
                    throw new Exception(Pcomm.IoErrorMsg(ret));
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
            finally
            {

            }
        }

        #endregion

        #region 下行接收线程数据处理
        // 创建一个并发队列作为缓存
        static ConcurrentQueue<byte[]> dataDownQueue = new ConcurrentQueue<byte[]>();

        // 定义处理统计数据的函数

        bool stopDownProcessing = false;
        public void ProcessDownData()
        {
            while (!stopDownProcessing)
            {
                // 从队列中获取数据
                if (dataDownQueue.TryDequeue(out byte[] data))
                {
                    // 进行数据处理和统计操作
                    // ...
                    ParseFrameAlice(data, data.Length);         //645协议帧接收解析扫描
                }
                else
                {
                    // 队列为空，可以选择等待一段时间再尝试获取数据
                    Thread.Sleep(100);
                }
            }
        }

        public Thread processDownThread;
        #endregion


        #region 中断发生回调函数收接串口数据[void DataReceived(int iPort)]
        /// <summary>
        /// 中断发生回调函数
        /// </summary>
        /// <param name="iPort">通讯端口号码</param>
        byte[] rec_buf = new byte[1024];
        int RxByteCnt = 0;
        private void DataReceived(int iPort)    //编写委托方法  串口数据接收中断
        {
            try
            {
                int rec_len = Pcomm.sio_read(iPort, rec_buf, 1024); //接收数据
                RxByteCnt += rec_len;
                if (rec_len > 0)                                    //串口有返回数据,数据长度rec_len rec_buf
                {
                    byte[] data = new byte[rec_len];
                    Array.Copy(rec_buf, data, rec_len);
                    dataDownQueue.Enqueue(data); // 将数据入队，指定入队的长度为 bytesRead
                    //this.ParseFrameAlice(rec_buf, rec_len);         //645协议帧接收解析扫描
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }
        #endregion


        #region 上行接收线程数据处理
        // 创建一个并发队列作为缓存
        static ConcurrentQueue<byte[]> dataUpQueue = new ConcurrentQueue<byte[]>();

        // 定义处理统计数据的函数

        bool stopUpProcessing = false;
        public void ProcessUpData()
        {
            while (!stopUpProcessing)
            {
                // 从队列中获取数据
                if (dataUpQueue.TryDequeue(out byte[] data))
                {
                    // 进行数据处理和统计操作
                    // ...
                    //ParseFrameAlice(data, data.Length);         //645协议帧接收解析扫描
                    this.ParseFrameHDLC(data, data.Length);       //645协议帧接收解析扫描
                }
                else
                {
                    // 队列为空，可以选择等待一段时间再尝试获取数据
                    Thread.Sleep(100);
                }
            }
        }

        public Thread processUpThread;
        #endregion


        #region 中断发生回调函数收接串口数据[void DataReceived(int iPort)]
        /// <summary>
        /// 中断发生回调函数
        /// </summary>
        /// <param name="iPort">通讯端口号码</param>
        private void UpDataReceived(int iPort)    //编写委托方法  串口数据接收中断
        {
            try
            {
                byte[] rec_buf = new byte[1024];
                int rec_len = Pcomm.sio_read(iPort, rec_buf, 1024); //接收数据	

                if (rec_len > 0)                                    //串口有返回数据,数据长度rec_len rec_buf
                {
                    byte[] data = new byte[rec_len];
                    Array.Copy(rec_buf, data, rec_len);
                    dataUpQueue.Enqueue(data);      // 将数据入队，指定入队的长度为 bytesRead
                                                    //this.ParseFrameAlice(rec_buf, rec_len);   //645协议帧接收解析扫描
                    //this.ParseFrameHDLC(rec_buf, rec_len);         //645协议帧接收解析扫描
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }
        #endregion

        #region FrameAlice接收数据解释[void ParseFrameAlice(byte[] rec_buf,int rec_len)]
        /// <summary>
        /// 接收数据解释
        /// </summary>
        /// <param name="rec_buf">接收数据</param>
        /// <param name="rec_len">接收长度</param>
        private void ParseFrameAlice(byte[] rec_buf, int rec_len)
        {
            int iStartPos = -1;      //起始位置

            if (isReceiving)
            {
                timer.Stop();
                timer.Start();
            }
            //判断接收缓冲区是否已经创建
            if (this.alRecBuf == null)
            {
                this.alRecBuf = new ArrayList();
            }

            //将当前接收数据存放缓冲区中
            for (int i = 0; i < rec_len; i++)
            {
                this.alRecBuf.Add(rec_buf[i]);
            }

        lab_next:


            //接收缓冲区大小
            int iBufLen = this.alRecBuf.Count;

            //检查帧头0x7D
            for (int i = 0; i < iBufLen; i++)
            {
                if ((byte)this.alRecBuf[i] == 0x7D)
                {
                    iStartPos = i;
                    isReceiving = true;
                    break;
                }
            }

            //不存在帧头0x68
            if (iStartPos == -1)
            {
                this.alRecBuf.Clear();
                return;
            }

            //检查帧数据长度
            if ((iBufLen - iStartPos) < 4)
            {
                return;
            }

            //检查帧帧头0x86
            if ((byte)this.alRecBuf[iStartPos + 1] != 0x86)
            {
                 this.alRecBuf.Clear();
                 return;
            }

            //数据长度
            int iDataLen1 = (byte)this.alRecBuf[iStartPos + 2];
            int iDataLen2 = (byte)this.alRecBuf[iStartPos + 3];
            int iDataLen = iDataLen1 + (iDataLen2<<8);

            //检查帧数据长度
            if ((iBufLen - iStartPos) < (10 + iDataLen))
            {
                return;
            }

            //检查帧帧尾0x41 9E
            if ((byte)this.alRecBuf[iStartPos + iDataLen + 8] != 0x41  || (byte)this.alRecBuf[iStartPos + iDataLen + 9] != 0x9E)
            {
                this.alRecBuf.Clear();
                return;
            }
            timer.Stop();
            if (ShowReceiceCommand != null)
            {
                //ShowReceiceCommand(this, bReceice, this.BytStringInsertSpace(this.sReturnData));
            }

            AliceMessage.Clear();
            byte[] byteArray = new byte[alRecBuf.Count];
            for (int i = 0; i < alRecBuf.Count; i++)
            {
                byteArray[i] = Convert.ToByte(alRecBuf[i]);
            }
            AliceMessage.Set(byteArray);
            if(ReceiveHandler != null)
            {
                ReceiveHandler(byteArray);
            }
            
            this.alRecBuf.Clear();
            isReceiving = false;
            nFound = 1;
        }


        #endregion

        #region FrameHDLC接收数据解释[void ParseFrameAlice(byte[] rec_buf,int rec_len)]
        /// <summary>
        /// 接收数据解释
        /// </summary>
        /// <param name="rec_buf">接收数据</param>
        /// <param name="rec_len">接收长度</param>
        private void ParseFrameHDLC(byte[] rec_buf, int rec_len)
        {
            int iStartPos = -1;      //起始位置
            int iChekSum = 0;        //校验码
            bool bValidFrame = true;
            StringBuilder sbData = new StringBuilder();

            if (isReceiving)
            {
                timer.Stop();
                timer.Start();
            }
            //判断接收缓冲区是否已经创建
            if (this.alRecBuf == null)
            {
                this.alRecBuf = new ArrayList();
            }

            //将当前接收数据存放缓冲区中
            for (int i = 0; i < rec_len; i++)
            {
                this.alRecBuf.Add(rec_buf[i]);
            }

            lab_next:

            bValidFrame = true;
            sbData = new StringBuilder();

            //接收缓冲区大小
            int iBufLen = this.alRecBuf.Count;

            //检查帧头0x7E
            for (int i = 0; i < iBufLen; i++)
            {
                if ((byte)this.alRecBuf[i] == 0x7E)
                {
                    iStartPos = i;
                    isReceiving = true;
                    break;
                }
            }

            //不存在帧头0x7E
            if (iStartPos == -1)
            {
                this.alRecBuf.Clear();
                return;
            }

            //检查帧数据长度
            if ((iBufLen - iStartPos) < 4)
            {
                return;
            }

            /*
            pCom->RxLen =  pCom->Buf[0] & 0x07;
            pCom->RxLen <<= 8;
            pCom->RxLen += pCom->Buf[1];
            */
            Byte tmp = (byte)((byte)this.alRecBuf[iStartPos + 1] & (byte)0xF0);
            //检查帧帧头0x86
            if (tmp != 0xA0)
            {
                this.alRecBuf.Clear();
                return;
            }

            //数据长度
            int iDataLen2 = (byte)((byte)this.alRecBuf[iStartPos + 1] & (byte)0x03);
            int iDataLen1 = (byte)this.alRecBuf[iStartPos + 2];
            int iDataLen = iDataLen1 + (iDataLen2 << 8);

            //检查帧数据长度
            if ((iBufLen - iStartPos) < (2 + iDataLen))
            {
                return;
            }

            //检查帧帧尾0x41 9E
            if ((byte)this.alRecBuf[iStartPos + iDataLen + 1] != 0x7E)
            {
                this.alRecBuf.Clear();
                return;
            }
            timer.Stop();
            if (ShowReceiceCommand != null)
            {
                //ShowReceiceCommand(this, bReceice, this.BytStringInsertSpace(this.sReturnData));
            }

            HDLCMessage.Clear();
            byte[] byteArray = new byte[alRecBuf.Count];
            for (int i = 0; i < alRecBuf.Count; i++)
            {
                byteArray[i] = Convert.ToByte(alRecBuf[i]);
            }
            HDLCMessage.Set(byteArray);
            if (ParserHandler != null)
            {
                ParserHandler(byteArray);
            }

            this.alRecBuf.Clear();
            isReceiving = false;
            nFound = 1;
        }


        #endregion

        public int SendToMeter(string strControlCode, string strData, out string strOutData)
        {
            strOutData = "0";
            string strResultInfo;
            int ret = -1;
            try
            {
                if (setResultHander != null)
                {
                    setResultHander("Communicating...");
                }

                if(setAlarmHander != null)
                {
                    setAlarmHander(Color.White);
                }

                this.OpenPort(gComm_iPort, gComm_iBaudRate, gComm_iDataBit, gComm_iStopBit, gComm_strParity);  //打开串口
                ret = this.ReadMeterWhile(gComm_iPort, gComm_strMeterAddress, strControlCode, strData.Length / 2, strData, false, gComm_Delay); //发送 接收 处理

                strResultInfo = DL645Unpack(sReturnData, out strOutData, gComm_strMeterAddress);
                if (setTextHander != null)
                {
                    setTextHander(strResultInfo+"\n");
                }

                if(strResultInfo.Contains("成功"))
                {
                    //setAlarmHander(Color.Green);
                }
                else
                {
                    setAlarmHander(Color.Red);
                }

                if (setResultHander != null)
                {
                    setResultHander("Ready");
                }

                this.ClosePort(gComm_iPort);                 //关闭串口

                //拆包，返回645 拆包结果,返回数据域和错误应答帧
            }
            catch (Exception ex)
            {
                if (setErrorHander != null)
                {
                    setErrorHander(ex.Message);
                }
                else
                {
                    throw new Exception(ex.Message);
                }
            }

            return ret;   //0成功  -1失败
        }


        public int SendToMeter(string strControlCode, string strData, out string strOutData, int iDelay)
        {
            strOutData = "0";
            string strResultInfo;
            int ret = -1;
            try
            {
                if (setResultHander != null)
                {
                    setResultHander("Communicating...");
                }
                if (setAlarmHander != null)
                {
                    setAlarmHander(Color.White);
                }

                this.OpenPort(gComm_iPort, gComm_iBaudRate, gComm_iDataBit, gComm_iStopBit, gComm_strParity);  //打开串口
                ret = this.ReadMeterWhile(gComm_iPort, gComm_strMeterAddress, strControlCode, strData.Length / 2, strData, false, iDelay); //发送 接收 处理

                strResultInfo = DL645Unpack(sReturnData, out strOutData, gComm_strMeterAddress);
                if (setTextHander != null)
                {
                    setTextHander(strResultInfo + "\n");
                }

                if (strResultInfo.Contains("成功"))
                {
                    //setAlarmHander(Color.Green);
                }
                else
                {
                    setAlarmHander(Color.Red);
                }

                if (setResultHander != null)
                {
                    setResultHander("Ready");
                }

                this.ClosePort(gComm_iPort);                 //关闭串口
                //拆包，返回645 拆包结果,返回数据域和错误应答帧
            }
            catch (Exception ex)
            {
                if (setErrorHander != null)
                {
                    setErrorHander(ex.Message);  //弹框
                }
                else
                {
                    throw new Exception(ex.Message);
                }
            }

            finally
            {
                
            }
            return ret;   //0成功  -1失败
        }


        /// <summary>
        /// 读电表数据  组帧 发送请求帧 接收帧
        /// </summary>
        /// <param name="iPort">串口号(1,2,3.....)</param>
        /// <param name="strAddress">表号</param>
        /// <param name="strControlCode">控制码</param>
        /// <param name="intLen">数据长度</param>
        /// <param name="strData">数据内容</param>
        /// <param name="bBroadCast">是否广播命令</param>
        /// <param name="iDelay">等时间(秒)</param>
        /// <returns>0成功，非0结果：失败</returns>  组帧 发送 接收
        public int ReadMeterWhile(int iPort, string strAddress, string strControlCode, int intLen, string strData, bool bBroadCast, int iDelay)
        {
            int ret = -1;
            StringBuilder sbSendData = new StringBuilder();     //组织发送帧

            ReturnData = "";                                    //保存发送帧
            SendData = "";                                      //保存返回帧
            string strHead = "";
            try
            {
                //加入帧头
                sbSendData.Append("68");                        //起始符68H
                if (strAddress.Length > 12)
                {
                    strAddress = strAddress.Substring(strAddress.Length - 12, 12);  //地址域
                }
                else if (strAddress.Length < 12)
                {
                    strAddress = strAddress.PadRight(12, '0');   //不足补0
                }


                //加入通讯地址
                //sbSendData.Append(this.HiToDi(strAddress));

                //加入帧头
                sbSendData.Append("68");

                //加入控制码
                sbSendData.Append(strControlCode);

                //数据长度
                sbSendData.Append(intLen.ToString("X2"));   //转成十六进制字符串

                //数据域 + 33
                for (int i = 0; i < intLen * 2; i += 2)       //数据域
                {
                    //int test = Convert.ToInt32("0A", 16);   //举例"0A"==>10
                    //string test1 = test.ToString("X2");     //举例10 ==>"0A"
                    int iniTemp = Convert.ToInt32(strData.Substring(i, 2), 16) + 0x33;  //转成十进制+33H
                    iniTemp = iniTemp % 256;                                              //取1个字节
                    sbSendData.Append(iniTemp.ToString("X2"));                          //转成字符型
                }

                //计算检验码
                string strTemp = sbSendData.ToString();
                int iLen = strTemp.Length;
                int iCheckSum = 0;
                for (int i = 0; i < iLen; i += 2)
                {
                    iCheckSum += Convert.ToInt32(strTemp.Substring(i, 2), 16); //调用类的静态方法
                    iCheckSum = iCheckSum % 0x100;
                }
                sbSendData.Append(iCheckSum.ToString("X2"));

                //加入结束符
                sbSendData.Append(16);      //sbSendData发送帧字符串

                //发送的字符串
                this.sReturnData = "";
                this.bReceice = false;

                //SendData = this.sSendData = this.BytStringInsertSpace("FEFEFEFE" + sbSendData.ToString());

                //byte[] send_buf = this.StringToByte(this.sSendData);    //字符串转成16进制!!!!!!!!!!!!!!!!!!!
                //int send_len = send_buf.Length;

                //ret = Pcomm.sio_write(iPort, send_buf, send_len);       //数据写入串口!!
                //if (ret != send_len)
                //{
                //    this.sReturnData = "";
                //    return -3;        //失败
                //}

                if (setTextHander != null)
                {
                    setTextHander(StringProcess.GetNowTime() + "TX=>:" + this.sSendData + "\n");    //打印发送报文
                }

                if (strAddress == "999999999999")                      //广播命令不等待应答
                {
                    return 0;                                         //广播地址不要求应答,无需等待接收数据
                }

                //等待接收数据
                for (int i = 0; i < iDelay; i++)          //等待串口返回数据
                {
                    if (this.sReturnData.Length > 0)    //等待接收完整帧
                    {
                        break;                            //接收到一帧完整645帧
                    }

                    System.Threading.Thread.Sleep(100);   //100ms
                }

                this.sSendData = this.sSendData.Replace(" ", "");

                if (sReturnData.Length != 0)
                {
                    strHead = "FE FE FE FE ";
                }
                else
                {
                    strHead = "";
                }
                if (setTextHander != null)
                {
                    setTextHander(StringProcess.GetNowTime() + "RX<=:" + strHead + this.sReturnData + "\n");
                }

                this.sReturnData = this.sReturnData.Replace(" ", "");
                if (this.bReceice)
                {
                    return 0;    //接收到一帧完整645帧
                }
                else
                {
                    return -1;   //接收数据非645正
                }

            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }
 

        #region  -33H
        public string Sub33H(string strData)
        {
            System.Text.StringBuilder sbRetData = new StringBuilder();
            int iLen = strData.Length;
            for (int i = 0; i < iLen; i += 2)
            {
                int iniTemp = Convert.ToInt32(strData.Substring(i, 2), 16);
                iniTemp = iniTemp < 0x33 ? iniTemp + 256 : iniTemp;
                iniTemp = iniTemp - 0x33;
                sbRetData.Append(iniTemp.ToString("X2"));
            }

            return sbRetData.ToString();

        }
        #endregion

        #region 返回帧拆包 解析
        /// <summary>
        /// 帧应答情况
        /// </summary>
        /// <param name="strTemp"></param> 返回帧
        /// <param name="OutData"></param> 数据域内容
        /// <returns> </returns> 帧解析结果
        public string  DL645Unpack(string strTemp, out string OutData, string strMeterAddress)
        {
            string reString = "";
            OutData = "";
            int iDataLen;
            if (strTemp != "")
            {
                iDataLen = 2 * Convert.ToInt32(strTemp.Substring(18, 2), 16);
                OutData = strTemp.Substring(20, iDataLen);
                OutData = Sub33H(OutData);
                switch (strTemp.Substring(16, 2)) //截取控制码
                {
                    case "C1":
                    case "C2":
                    case "C3":
                    case "C4":
                        {
                            int iErr = Convert.ToInt16(strTemp.Substring(20, 2));
                            int iFfsjEr = iErr & 1;    //非法数据
                            int iSignEr = iErr & 2;    //数据标识错
                            int iMaEr = iErr & 4;      //密码错误
                            int iNssc = iErr & 16;     //年时区数超
                            int iRdsc = iErr & 32;     //日段数超
                            int iFlsc = iErr & 64;     //费率数超
                            if (iMaEr == 4)
                            {
                                return reString = "编程失败，密码权限或密码错误,请重新输入有效值！";
                            }
                            if (iFfsjEr == 1)
                            {
                                return reString = "编程失败，非法数据";
                            }
                            if (iSignEr == 2)
                            {
                                return reString = "编程失败，数据标识错 ";
                            }
                            if (iNssc == 16)
                            {
                                return reString = "编程失败，年时区数超 ";
                            }
                            if (iRdsc == 32)
                            {
                                return reString = "编程失败，日段数超 ";
                            }
                            if (iFlsc == 64)
                            {
                                return reString = "编程失败，费率数超 ";
                            }
                            break;
                        }
                    case "D0":
                        return reString = "最大需量清零 失败 ×";
                    case "90":
                        return reString = "最大需量清零 成功  √";
                    case "8C":
                        switch (strTemp.Substring(20, 2))
                        {
                            case "33":
                                return reString = "电表波特率成功更改为 1200.";
                            case "43":
                                return reString = "电表波特率成功更改为 2400.";
                            case "53":
                                return reString = "电表波特率成功更改为 4800.";
                            case "73":
                                return reString = "电表波特率成功更改为 9600.";
                            case "32":
                                return reString = "32";
                        }
                        break;
                    case "81":
                        OutData = OutData.Substring(4, OutData.Length - 4);
                        return reString = "读取成功√";
                    case "91":
                        return reString = "读取成功√";
                    case "93":
                        //OutData = HiToDi(OutData);
                        return reString = "读取设备通讯地址成功√";
                        break;

                    case "95":
                        //OutData = HiToDi(OutData);
                        return reString = "设置设备通讯地址成功√";
                        break;
                    case "84":
                    case "8A":
                        return reString = "写入成功  √";
                    case "94"://DL645/2007
                        if (strTemp.Substring(18, 2) == "00")
                            return reString = "成功  √";
                        break;
                    case "8F"://修改密码命令
                        if (strTemp.Substring(18, 2) == "04")
                            return reString = "成功  √";
                        break;
                    case "D4"://DL645/2007
                    case "D1":
                        {
                            int iErr = Convert.ToInt16(strTemp.Substring(20, 2));
                            int iErrByte0 = iErr & 1;    //其他错误
                            int iErrByte1 = iErr & 2;    //无请求数据
                            int iErrByte2 = iErr & 4;    //密码错/未授权
                            int iErrByte3 = iErr & 8;   //通信整速率不能更改
                            int iErrByte4 = iErr & 16;   //年时区数超
                            int iErrByte5 = iErr & 32;   //日时段数超
                            int iErrByte6 = iErr & 64;   //费率数超

                            if (iErrByte0 == 1)
                            {
                                return reString = "编程失败，其他错误";
                            }
                            if (iErrByte1 == 2)
                            {
                                return reString = "编程失败，无请求数据 ";
                            }
                            if (iErrByte2 == 4)
                            {
                                return reString = "编程失败，密码错/未授权";
                            }
                            if (iErrByte3 == 8)
                            {
                                return reString = "编程失败，通信整速率不能更改";
                            }
                            if (iErrByte4 == 16)
                            {
                                return reString = "编程失败，年时区数超 ";
                            }
                            if (iErrByte5 == 32)
                            {
                                return reString = "编程失败，日时段数超 ";
                            }
                            if (iErrByte6 == 64)
                            {
                                return reString = "编程失败，费率数超 ";
                            }
                            break;
                        }

                }
                if (strTemp.Substring(26, 2) == "34")
                {
                    return reString = "无数据可读";
                }
            }
            else
            {
                if (strMeterAddress == "999999999999") return ("广播发送成功");
                return reString = "通信失败，无响应帧，请检查！";
            }
            return reString;
        }

        #endregion


 
        public int Send(Byte[] data, int iDelay)
        {
            if (ParserHandler != null)
            {
                ParserHandler(data);   //打印发送帧解析
            }
            nFound = -1;
            int ret = Pcomm.sio_write(gComm_iPort, data, data.Length);     //数据写入串口!!
            return ret;
        }

        public int Send(Byte[] data)
        {
            //if (ParserHandler != null)
            //{
            //    ParserHandler(data);   //打印发送帧解析
            //}
            //nFound = -1;
            int ret = Pcomm.sio_write(gComm_iPort, data, data.Length);     //数据写入串口!!
            return ret;
        }


        public bool Receive<T>(ReceiveParameters<T> args)
        {
            int waitTime;



            //Wait until reply occurred.		

            int LastBuffSize = 0;
            DateTime StartTime = DateTime.Now;
            bool retValue = true; //
            do
            {
                waitTime = (int)(DateTime.Now - StartTime).TotalMilliseconds;
                if (waitTime > args.WaitTime)
                {
                    return false;
                }

            }
            while (nFound == -1);

            args.Reply = (T)(object)AliceMessage;
            return (retValue);
                
        }

    }
}
